import { StringUtils } from '@/utils/StringUtils'

function containsEncodedComponents(x) {
  // ie ?,=,&,/ etc
  return decodeURI(x) !== decodeURIComponent(x)
}

export class PageUtil {
  /**
   * @deprecated
   * @param params
   * @returns {string}
   */
  static obj2params(params = null) {
    let obj = params
    if (obj === null || obj === undefined) {
      return ''
    }
    let str = []
    let len = Object.entries(obj).length
    let stringified = ['object', 'array']
    Object.entries(obj).forEach(([key, value], index) => {
      let _value = value
      if (stringified.includes(typeof _value)) {
        _value = JSON.stringify(_value)
      }

      if (index === len - 1) {
        str.push('?')
        str.push(key + '=' + _value)
      } else if (index === 0) {
        str.push('?')
        str.push(key + '=' + _value + '&')
      } else if (index <= len - 2) {
        str.push(key + '=' + _value + '&')
      } else if (index <= len - 1) {
        str.push(key + '=' + _value)
      }
    })
    let _res = str.join('')

    return _res
  }

  /**
   *
   * @param {String} id the ID of event;
   * @param {function} cb page event callback,due to uni.$emit;
   * @param {Object} options  route options
   * @param {String} options.route  route path
   * @param {Object} options.params  the onLoad() method's parameters, use {@link parseParam} for parsing.
   * @param {Boolean} options.redirect  use redirectTo()?
   * @returns {string} event_id event Id
   *
   * @example
   * PageUtil.addEvent('addEvent',()=>{
   *  // TODO
   * },{
   *       route:'../page/index',
   *       params:{'row':{a:1}},
   *      redirect:false
   * })
   */
  static addEvent(id, cb, options = {}) {
    let _evId = [(id || 'page-event'), '--page-event--'].join('')
    PageUtil._putEvent(_evId)
    uni.$on(_evId, (e) => {
      if (cb && typeof cb === 'function') {
        cb(e)
      }
    })
    let { route, params, redirect = false } = options || {}
    if (StringUtils.isEmptyOrNull(route)) {
      return ''
    }
    PageUtil.push(
      route,
      {
        __page_param: Object.assign({},
          params,
          { __eventId__: _evId }
        )
      },
      redirect
    )

    return _evId
  }

  emit(id, data) {
    let _evId = [(id || 'page-event'), '--page-event--'].join('')
    uni.$emit(_evId, data)
  }

  /**
   * use this method to avoid to parse parameters of onLoad method;<br/>
   * It requires to use {@link push}  or {@link addEvent}
   * @param onLoadParam
   * @returns {number|Object|Array}
   */
  static parseParam(onLoadParam) {
    console.debug('[page load params]', onLoadParam)
    let { pm } = onLoadParam || {}
    let decode = pm
    try {
      decode = decodeURIComponent(pm)
    }catch (e){
      console.warn('Maybe the uri does not need to decode.')
    }

    let { __page_param } = StringUtils.parseJson(decode, {})
    let res = { ...__page_param }
    return res
  }

  static push(route, params = null, redirect = false) {
    let _params = ['?pm=', encodeURIComponent(JSON.stringify(params))].join('')
    // let _params = PageUtil.obj2params(params);
    let url = route + _params
    console.debug('[push]url=>', url)
    if (typeof route === 'string') {
      uni[redirect ? 'redirectTo' : 'navigateTo']({
        url
      })
    }
  }

  static emitPageEvent(params = null) {
    let event = uni.getStorageSync('__page_current_event_id')
    if (StringUtils.isEmptyOrNull(event)) {
      throw new Error('page event is not defined.')
    }
    console.debug('[PAGE EVENT EMITTED] ', event)
    uni.$emit(event, params)
    PageUtil._remove_current_event()
  }

  static back(delta = 1) {
    uni.navigateBack({
      delta: delta
    })
  }


  static rnd(min, max) {
    return Math.floor(min + (Math.random() * (max - min + 1)))
  }

  static uid(len = 8) {
    let char = '789456132QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
    let chars = char.split('')
    let str = []
    for (let i = 0; i < len; ++i) {
      let randomIndex = PageUtil.rnd(0, chars.length - 1)
      str.push(chars[randomIndex])
    }
    console.debug(str.join(''))
    return str.join('')
  }

  static _set_current_event(id) {
    uni.setStorageSync('__page_current_event_id', id)
  }

  static _remove_current_event() {
    uni.removeStorageSync('__page_current_event_id')
  }

  static _putEvent(id) {
    let storeName = '__pageEvents'
    let events = uni.getStorageSync(storeName)
    if (StringUtils.isEmptyOrNull(events)) {
      console.debug('[Page Event] Init events [/]')
      uni.setStorageSync(storeName, JSON.stringify([]))
    }
    events = StringUtils.parseJson(uni.getStorageSync(storeName), [])
    let eventIndex = events.indexOf(id)
    if (eventIndex >= 0) {
      uni.$off(events[eventIndex])
      console.debug('[Page Event] cleared 1 event-> [-]', events[eventIndex])
      events.splice(eventIndex, 1)
    }
    events.push(id)
    PageUtil._set_current_event(id)
    uni.setStorageSync(storeName, JSON.stringify(events))

    events = StringUtils.parseJson(uni.getStorageSync(storeName), [])
    console.debug('[Page Event] event is being added-> [+]', id)
    console.debug('[Page Event] Current events->', events)
  }

  static disposeEvents() {
    let storeName = '__pageEvents'
    let events = StringUtils.parseJson(uni.getStorageSync(storeName), [])
    events.forEach(ev => {
      console.warn('[Page Event Dispose] [-]', ev)
      uni.$off(ev)
    })
  }


  static removeEvent(evId) {
    uni.$off(evId)
  }
}
